package com.drcoffee.drcoffeemall.service.impl;

import com.drcoffee.drcoffeemall.entry.*;
import com.drcoffee.drcoffeemall.mapper.AddressMapper;
import com.drcoffee.drcoffeemall.mapper.UserMapper;
import com.drcoffee.drcoffeemall.service.UserService;
import com.drcoffee.drcoffeemall.util.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


/*
 * 用户
 * */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public class UserServiceImpl implements UserService {
    final
    UserMapper userMapper;
    final
    RedisTemplate<String, Object> redisTemplate;
    final
    AddressMapper addressMapper;
    final
    OSSUtil ossUtil;

    private final EmailUtil emailUtil;

    private final VerifyCodeUtil verifyCodeUtil;

    public UserServiceImpl(EmailUtil emailUtil, OSSUtil ossUtil, AddressMapper addressMapper, UserMapper userMapper, RedisTemplate<String, Object> redisTemplate, VerifyCodeUtil verifyCodeUtil) {
        this.emailUtil = emailUtil;
        this.ossUtil = ossUtil;
        this.addressMapper = addressMapper;
        this.userMapper = userMapper;
        this.redisTemplate = redisTemplate;
        this.verifyCodeUtil = verifyCodeUtil;
    }

    /* 校验账号是否已被注册 */
    public Result verifyAccount(String account) {
        try {
            Integer resultVerifyAccount = userMapper.verifyAccount(account);
            if (resultVerifyAccount != 0) {
                return new Result(2, "SUCCESS", "The account has been registered", null);
            } else {
                return new Result(1, "SUCCESS", "", null);
            }
        } catch (Exception e) {
            log.error("===================== verifyAccount()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }


    /*
     * 注册
     * */
    @Override
    public Result register(User user) throws GeneralSecurityException {
        try {
            user.setPassword(RSAUtil.decrypt(user.getPassword()));
            if (user.getInvitation_code() != null) {
                // 根据邀请码查询出相关企业信息
                InvitationCode invitationCode = userMapper.invitationCheck(user.getInvitation_code());
                if (invitationCode != null) {
                    // 企业用户
                    if (invitationCode.getErp_code().equals("552204001")) {
                        user.setPermission_id(3);
                    } else {
                        user.setPermission_id(1);
                    }
                    user.setInvitation_code(Integer.valueOf(invitationCode.getCode()));
                    user.setFirm_name(invitationCode.getFirm_name());
                    user.setInvoice_title(invitationCode.getInvoice_title());
                    user.setInvoice_number(invitationCode.getInvoice_number());

                    user.setDiscount_one(invitationCode.getDiscount_one());
                    user.setDiscount_two(invitationCode.getDiscount_two());
                    user.setErp_code(invitationCode.getErp_code());
                    userMapper.setInvitationCheckStatus("Y", invitationCode.getCode());
                } else {
                    return new Result(2, "SUCCESS", "Invalid invitation code", null);
                }
            } else {
                // 个人用户
                user.setPermission_id(0);
                user.setErp_code("552204001");
            }
            // 密码加密
            String encrypt_password = EncipherPassUtil.encrypt(user.getPassword());
            user.setPassword(encrypt_password);

            //添加用户
            userMapper.register(user);

            Address address = user.getAddress();
            if (address != null) {
                // 添加地址
                addressMapper.addAddress(address);
                setDefaultAddress(address.getId(), address.getUser_account());
            }
//            String verifyCode = (String) redisTemplate.opsForValue().get(user.getEmail());
//            if (verifyCode != null) {
//                redisTemplate.delete(user.getEmail());
//            }
            return new Result(1, "SUCCESS", "Registered successfully", null);
        } catch (Exception e) {
            log.error("===================== register()异常： =====================", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }


    /*
     * 账号登录校验
     * */
    @Override
    public Result accountLogin(User user) {
        try {
            // 解密密码
            String pass = RSAUtil.decrypt(user.getPassword());
            String userPass = userMapper.getUserPass(user.getAccount());
            if (userPass == null || userPass.isEmpty()) {
                return new Result(2, "SUCCESS", "The account or password is incorrect", null);
            }
            String decrypt_pass = EncipherPassUtil.decrypt(userMapper.getUserPass(user.getAccount()));
            // 密码校验
            if (pass.equals(decrypt_pass)) {
                User selUser = userMapper.accountLogin(user);
                selUser.setPassword(null);
                String token = CreatJwtUtil.getoken(userMapper.accountLogin(user));
                redisTemplate.opsForValue().set(token, selUser, 30 * 60, TimeUnit.SECONDS);
                Map<String, Object> resultMap = new HashMap<>();
                resultMap.put("token", token);
                resultMap.put("user", selUser);
                return new Result(1, "SUCCESS", "Login successful", resultMap);
            } else {
                return new Result(2, "SUCCESS", "The account or password is incorrect", null);
            }
        } catch (Exception e) {
            log.error("===================== accountLogin()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    /*
     * 验证码登录
     * */
    @SneakyThrows
    @Override
    public ResponseEntity<Object> codeLogin(String key, String code, Integer type) {
        String cache_code = (String) redisTemplate.opsForValue().get(key);
        System.out.println("-=-----------------------------");
        System.out.println(cache_code);
        System.out.println("-=-----------------------------");
        Result result;
        if (cache_code != null && Objects.equals(code, cache_code)) {
            User user = null;
            if (type == 2) {
                user = userMapper.getUserByPhoneOrEmail("email", key); // 邮箱验证
            } else if (type == 1) {
                user = userMapper.getUserByPhoneOrEmail("phone", key); // 手机验证
            }
            if (user != null) {
                user.setPassword(null);
                // 判断国外用户是否初次登录
                if (!Objects.equals(user.getAccount(), "") && user.getAccount() != null) {
                    // 不是初次登录正常返回Token
                    Map<String, Object> resultMap = new HashMap<>();
                    String token = CreatJwtUtil.getoken(user);
                    redisTemplate.delete(key);
                    redisTemplate.opsForValue().set(token, user, 30 * 60, TimeUnit.SECONDS);
                    resultMap.put("token", token);
                    resultMap.put("user", user);
                    result = new Result(1, "", "", resultMap);
                } else {
                    result = new Result(0, "", "", null);
                }
            } else {
                result = new Result(3, "", "", null); // 该邮箱/手机号未注册
            }
        } else {
            result = new Result(2, "", "", null); // 验证码错误
        }
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /* 删除Token */
    @Override
    public boolean removeToken(String Token) {
        redisTemplate.delete(Token);
        Object obj = redisTemplate.opsForValue().get(Token);
        return obj == null;
    }

    /* 更新Token有效期 */
    @Override
    public void renewalToken(String Token) {
        redisTemplate.expire(Token, 30 * 60, TimeUnit.SECONDS);
    }

    /* 校验Token */
    @Override
    public boolean verifyToken(String Token, ExceptionRecord exceptionRecord) {
        try {
            System.out.println("999999999999999999999999999999999999999"+Token);
            User user = (User) redisTemplate.opsForValue().get(Token);
            return user != null;
        } catch (IllegalArgumentException e) {
            log.error("===================== verifyToken()异常： =====================" + e.getMessage());
            userMapper.setExceptionRecord(exceptionRecord);
            return false;
        }
    }

    /*
     * 判断是否为管理员
     * */
    @Override
    public Map<String, Object> allPermissionCheck(String token) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            User redis_user = (User) redisTemplate.opsForValue().get(token);
            if (redis_user != null) {
                User user = (User) getUserByAccount(redis_user.getAccount()).getObject();
                resultMap.put("result", user.getPermission_id() == 0);
            }
        } catch (Exception e) {
            resultMap.put("message", "失败");
            resultMap.put("reason", e.getMessage());
            log.error("===================== allPermissionCheck()异常： =====================", e);
        }
        return resultMap;
    }

    /*
     * 校验邮箱验证码
     * */
    @Override
    public boolean verifyEmailCode(String email, String emailCode) {
        return verifyCodeUtil.checkVerifyCode(email, emailCode);
    }

    /*
     * 修改用户信息
     * */
    @Override
    public Map<String, Object> uploadUser(User user) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            boolean result = userMapper.uploadUser(user);
            resultMap.put("result", result);
            resultMap.put("message", "修改成功");
        } catch (Exception e) {
            resultMap.put("result", false);
            resultMap.put("message", "修改失败");
            resultMap.put("error", e.getMessage());
        }
        return resultMap;
    }

    /*
     * 修改用户头像
     * */
    @Override
    public Result uploadUserPhoto(Integer id, String val1, String val2) {
        try {
            userMapper.uploadUserPhoto(id, val1);
            if (!Objects.equals(val2, "")) {
                // 删除旧的头像
                String path = userMapper.getAvatarPath();
                ossUtil.deleteFile(path + val2);
            }
            return new Result(1, "SUCCESS", "", null);
        } catch (Exception e) {
            log.error("===================== uploadUserPhoto()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    @Override
    public Result sendLoginCode(String val) {
        try {
            // 判断手机号或邮箱是否存在
            User user = userMapper.getUserByCE(val);
            if (user != null) {
                if (Objects.equals(user.getPhone(), val)) {
                    //发送手机验证码
                    log.info("===================== 发送手机验证码 =====================");
                } else if (Objects.equals(user.getEmail(), val)) {
                    //发送邮箱验证码
                    log.info("===================== 发送邮箱验证码 =====================");
                    sendEmailCode(val, 2);
                }
                return new Result(1, "SUCCESS", "", null);
            } else {
                // 邮箱或手机号不存在
                return new Result(2, "SUCCESS", "The email address or mobile number does not exist", null);
            }
        } catch (Exception e) {
            log.error("===================== sendLoginCode()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    /* 发送邮箱验证码(找回密码) */
    @Override
    public boolean sendEmailCode(String email, Integer type) {
        String verifyCode = (String) redisTemplate.opsForValue().get(email);
        if (verifyCode != null) {
            return true;
        } else {
            String code = VerifyCodeUtil.generateVerifyCode(6);
            boolean result = emailUtil.sendEmailGo(type, null, email, code, null);
            if (result) {
                redisTemplate.opsForValue().set(email, code, 15L, TimeUnit.MINUTES);
            }
            return result;
        }
    }

    /* 判断邮箱或手机是否存在 */
    @Override
    public ResponseEntity<Object> isExist(String val) {
        return new ResponseEntity<>(userMapper.isExist(val), HttpStatus.OK);
    }

    /*
     * 找回密码
     * */
    @Override
    public Result retrievePass(Map<String, Object> reval) throws GeneralSecurityException {
        try {
            String email = (String) reval.get("email");
            String code = (String) redisTemplate.opsForValue().get(email);
            if (code != null && Objects.equals(reval.get("email_code"), code)) {
                // 密码加密
                String password = EncipherPassUtil.encrypt(RSAUtil.decrypt((String) reval.get("password")));
                // 修改密码
                userMapper.retrievePass(email, password);
                // 删除验证码
                redisTemplate.delete(email);
                // 密码重置成功
                return new Result(1, "SUCCESS", "Password reset succeeded", null);
            } else {
                // 验证码校验失败
                return new Result(2, "SUCCESS", "The verification code fails. Procedure", null);
            }
        } catch (Exception e) {
            log.error("===================== retrievePass()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    /*
     * 更改密码
     * */
    @Override
    public Result changePass(Map<String, Object> val) {
        try {
            String account = (String) val.get("account");
            String oldPass = RSAUtil.decrypt((String) val.get("oldPass"));
            String newPass = RSAUtil.decrypt((String) val.get("password"));
            // 判断原密码是否正确
            // 密码校验
            Integer passResult = userMapper.verifyPass(account, oldPass);
            if (passResult == 1) {
                boolean changeResult = userMapper.changePass(account, newPass);
                return new Result(1, "SUCCESS", "Password changed successfully", null);
            } else {
                // 原密码错误
                return new Result(2, "SUCCESS", "Old password error", null);
            }
        } catch (Exception e) {
            log.error("===================== changePass()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    /*
     * 更改邮箱
     * */
    @Override
    public Result changeEmPh(String Token, String v1, String v2, String v3) {
        try {
            User user = (User) redisTemplate.opsForValue().get(Token);
            String account = null;
            if (user != null) {
                account = user.getAccount();
            }
            Integer exist = userMapper.isExist(v1);
            if (exist > 0) {
                return new Result(3, "SUCCESS", "has been bound", null);
            } else {
                // 验证码校验
                boolean codeResult = verifyCodeUtil.checkVerifyCode(v1, v2);
                if (codeResult) {
                    if (Objects.equals(v3, "P")) {
                        userMapper.changePhone(account, v1);
                    } else if (Objects.equals(v3, "E")) {
                        userMapper.changeEmail(account, v1);
                    }
                    User new_user = userMapper.accountLogin(user);
                    redisTemplate.opsForValue().set(Token, new_user, 30 * 60, TimeUnit.SECONDS);
                    return new Result(1, "SUCCESS", "Email changed successfully", null);
                } else {
                    // 验证码错误
                    return new Result(2, "SUCCESS", "Verification code error", null);
                }
            }

        } catch (Exception e) {
            log.error("===================== changeEmPh()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    @Override
    public Result changeName(String Token, String newName) {
        try {
            User user = (User) redisTemplate.opsForValue().get(Token);
            String account = null;
            if (user != null) {
                account = user.getAccount();
            }
            // 验证码校验
            boolean changeResult = userMapper.changeName(account, newName);
            return new Result(1, "SUCCESS", "Name changed successfully", null);
        } catch (Exception e) {
            log.error("===================== changeName()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }

    }

    @Override
    public Result setAccount(User user) {
        try {
            // 密码加密
            user.setPassword(EncipherPassUtil.encrypt(RSAUtil.decrypt(user.getPassword())));
            //添加用户
            userMapper.setAccount(user);
            Address address = user.getAddress();
            if (address != null) {
                // 添加地址
                addressMapper.addAddress(address);
                setDefaultAddress(address.getId(), address.getUser_account());
            }
            User new_User = userMapper.accountLogin(user);
            new_User.setPassword(null);
            // 添加新的Token
            String new_Token = CreatJwtUtil.getoken(new_User);
            redisTemplate.opsForValue().set(new_Token, new_User, 30 * 60, TimeUnit.SECONDS);
            // 返回新的user
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", new_Token);
            resultMap.put("user", new_User);
            return new Result(1, "SUCCESS", "", resultMap);
        } catch (Exception e) {
            log.error("===================== setAccount()异常： =====================", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    @Override
    public Result invitationCheck(Integer code) {
        try {
            InvitationCode invitationCode = userMapper.invitationCheck(code);
            if (invitationCode != null) {
                return new Result(1, "SUCCESS", "", invitationCode);
            } else {
                return new Result(2, "ERROR", "", null);
            }
        } catch (Exception e) {
            log.error("===================== invitationCheck()异常： =====================", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    @Override
    public Result sendPhoneCode(String phone) {
        try {
            String code = VerifyCodeUtil.generateVerifyCode(6);
            Sample.sendPhoneCode(phone, code, "SMS_286790042");
            redisTemplate.opsForValue().set(phone, code, 5L, TimeUnit.MINUTES);
            return new Result(1, "SUCCESS", "", null);
        } catch (Exception e) {
            log.error("===================== sendPhoneCode()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    @Override
    public Result verifyCode(String v1, String v2, String v3) {
        try {
            String code = (String) redisTemplate.opsForValue().get(v1);
            if (!Objects.equals(code, "") && Objects.equals(code, v2)) {
                if (Objects.equals(v3, "T")) {
                    redisTemplate.delete(v1);
                }
                return new Result(1, "SUCCESS", "", null);
            } else {
                return new Result(2, "SUCCESS", "", null);
            }
        } catch (Exception e) {
            log.error("===================== verifyCode()异常： =====================", e);
            return new Result(-1, "SUCCESS", e.getMessage(), null);
        }
    }

    /*
     * 添加反馈
     * */
    @Override
    public Result putFeedback(String Token, Feedback feedback) {
        try {
            User user = (User) redisTemplate.opsForValue().get(Token);
            feedback.setUser_account(user.getAccount());
            userMapper.putFeedback(feedback);
            return new Result(1, "SUCCESS", "", null);
        } catch (Exception e) {
            log.error("===================== putFeedback()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    @Override
    public Result getAlterFirmPD(String account) {
        try {
            Integer number = userMapper.getAlterFirmPD(account);
            return new Result(1, "SUCCESS", "", number);
        } catch (Exception e) {
            log.error("===================== getAlterFirmPD()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    /*
     * 添加企业变更申请
     * */
    @Override
    public Result addFirmAlter(FirmAlter firmAlter) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            userMapper.addFirmAlter(firmAlter);
            return new Result(1, "SUCCESS", "", null);
        } catch (Exception e) {
            log.error("===================== addFirmAlter()异常： =====================", e);
            return new Result(1, "ERROR", e.getMessage(), null);
        }
    }

    @Override
    public ResponseEntity<Integer> haveRegistered(String email) {
        Integer resultQuantity = userMapper.haveRegistered(email);
        if (resultQuantity == 0) {
            return new ResponseEntity<>(2, HttpStatus.OK);
        } else {
            return new ResponseEntity<>(1, HttpStatus.OK);
        }
    }

    /* 根据账号查询用户 */
    public Result getUserByAccount(String account) {
        try {
            User user = userMapper.getUserByAccount(account);
            user.setPassword(null);
            return new Result(1, "SUCCESS", "", user);
        } catch (Exception e) {
            log.error("===================== getUserByAccount()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

    /*
     * 判断是否为第一个地址，若为第一个则为默认地址
     * */
    public Result setDefaultAddress(Integer address_id, String account) {
        try {
            userMapper.setDefaultAddress(address_id, account);
            return new Result(1, "SUCCESS", "", null);
        } catch (Exception e) {
            log.error("===================== setDefaultAddress()异常： =====================", e);
            return new Result(-1, "ERROR", e.getMessage(), null);
        }
    }

}
